
#include <map>
#include "hzkHandler.h"
#ifdef MINI_GLOG
#include "miniglog/logging.h"
#endif

std::string gHzkFileName;
int gHzSize=24;
const unsigned int gHzkFullSize=1587312; //ascii's data's base address
void testPrintHzkdz(const char* content);
FILE* openHzkFile(const char* hzkFileName);

//打印点阵缓冲区（逐列逆序）为字符点阵  每3个字节是一列
void printHzkHex(const char *buffer, int bufferLen)
{
    char str[30];
    int cols=bufferLen/3; //24 or 12
    int rows=24;
    int k=0;
    memset(str, 0, sizeof(str));
    //打印列头
    for(int m=0;m<cols;++m){
        str[m]='0'+m%10;
    }
    LOG(INFO)<<str;
//逐列 逆向（第1点是低位）
    for(int i=0;i<rows;i++){
        memset(str, 0, sizeof(str));
        sprintf(str,"%-2d",i+1);
        for(int j=0;j<cols;j++){
            char mask=1<<(i%8);
            bool isShow=buffer[i/8+j*3] & mask;
            str[j+2]=isShow?'*':' ';
        }
        LOG(INFO)<<str;
    }
}
void  printBufferHex(const char *buffer, int bufferLen)
{
    char tmp[10];
    int i;
    LOG(INFO)<<"printBufferHex() ---------bufferLen=" <<bufferLen;
    for(i = 0; i < bufferLen; ++i) {
        sprintf(tmp, "%02d: %02x", i,buffer[i] & 0x0ff);
        LOG(INFO)<<tmp;
    }
    LOG(INFO)<<"printBufferHex() ---------end";

}

//取GBK汉字的索引号
//code=buf[0]*256+buf[1];
int font_gbk(unsigned short code)
{
    unsigned char bl=(code>>8)&0xFF;
    unsigned char bh=code &0xFF;
    unsigned int offset=0;
    if(bl>=0x81 && bl<=0xA0)//GBK/3: 81~A0 190*32=6080
    {
        offset=(bl-0x81)*190+(bh-0x40);
    }
    else if(bl>=0xA1 && bl<=0xA7)//GBK/1: A1~A7 94*7=658
    {
        offset=(bl-0xA1)*94+(bh-0xA1)+6080;
    }
    else if(bl>=0xA8 && bl<=0xA9)//GBK/1与GBK/5合并区 A8 A9 190*2=380
    {
        offset=(bl-0xA8)*190+(bh-0x40)+6080+658;
    }
    else if(bl>=0xAA && bl<=0xAF)//GBK/4 AA~AF 96*6=576
    {
        offset=(bl-0xAA)*96+(bh-0x40)+6080+658+380;
    }
    else if(bl>=0xB0 && bl<=0xF7)//GBK/4与GBK/2合并区 B0~F7 190*72=13680
    {
        offset=(bl-0xB0)*190+(bh-0x40)+6080+658+380+576;
    }
    else if(bl>=0xF8 && bl<=0xFE)//GBK/4 F8~FE  96*7=672
    {
        offset=(bl-0xF8)*96+(bh-0x40)+6080+658+380+576+13680;
    }
    if(bh>0x7F){offset--;}
    return offset;
}
//将像素值设置到点阵buffer中的指定坐标点
// dest 点阵数据缓冲区，已按hPixelCnt*vPixelCnt分配使用空间（至少hPixelCnt*vPixelCnt/8字节）
// isPixelShow是否显示（true该点数据位为1，否则为0）
// x横坐标
// y纵坐标
// isRow是否逐行
// isReverse是否逆向(第1个像素是字节中的低位)
void setPixel(char *dest, int hPixelCnt, int vPixelCnt, bool isPixelShow, int x, int y, bool isRow, bool isReverse)
{
    int byteIndex;
    int bitIndex;
    int widthBytes;
    char pval=isPixelShow?0x01:0x00;
    if(isRow){
        widthBytes=hPixelCnt/8;
        byteIndex=y*widthBytes+x/8;
        if(isReverse){
            bitIndex=x%8;
        }else{
            bitIndex=7-x%8;
        }
    }else{
        widthBytes=vPixelCnt/8;
        byteIndex=x*widthBytes+y/8;
        if(isReverse){
            bitIndex=y%8;
        }else{
            bitIndex=7-y%8;
        }
    }
    dest[byteIndex] |= (pval << bitIndex);
}

//将点阵buffer数据转换（逐行/逐列，正向/逆向转换）。逆向方式(第1个像素是字节中的低位)
// buffSrc 源点阵
// buffDest 目标点阵（输出参数）
// hPixelCnt 水平像素数量（必须是8的整数倍）
// vPixelCnt 垂直像素数量（必须是8的整数倍）
// isSrcRow 源点阵：true逐行方式显示 false逐列方式显示
// isDestRow目标点阵：true逐行方式显示 false逐列方式显示
// isSrcReverse 源点阵：true逆向 false顺向
// isDestReverse 目标点阵：true逆向 false顺向
int convertHzPixel(const char* buffSrc, char* buffDest, int hPixelCnt, int vPixelCnt,
        bool isSrcRow, bool isDestRow, bool isSrcReverse, bool isDestReverse)
{
    int x, y;
    int srcByteIndex;
    char pixelValue;//!=0表示显示该像素
    char pixelMask;
    int oneHzSize=hPixelCnt*vPixelCnt/8;
    int srcWidthBytes=hPixelCnt/8;
    if(!isSrcRow){
        srcWidthBytes=vPixelCnt/8;
    }
    memset(buffDest, 0, oneHzSize);
    for(srcByteIndex=0;srcByteIndex<oneHzSize;++srcByteIndex){
        for(int i=0;i<8;++i){
            if(isSrcRow){
                x=8*(srcByteIndex%srcWidthBytes);
                y=srcByteIndex/srcWidthBytes;
                if(isSrcReverse){
                    x+=i;
                }else{
                    x+=7-i;
                }
            }else{
                y=8*(srcByteIndex%srcWidthBytes);
                x=srcByteIndex/srcWidthBytes;
                if(isSrcReverse){
                    y+=i;
                }else{
                    y+=7-i;
                }
            }
            pixelMask=0x01 << i;
            pixelValue=buffSrc[srcByteIndex] & pixelMask;
            setPixel(buffDest, hPixelCnt, vPixelCnt, pixelValue!=0, x, y, isDestRow, isDestReverse);
        }
    }
    return 0;
}
/**********************************
* 得到ascii字符的字模信息，存入数组
* 参数：
*   *c:要得到字模信息的字符指针(len == 2)
*   buffer[]:存储字模信息的数组
* 无返回值
***********************************/
bool getAscCode(const char *c, FILE* HZK, int hPixelCnt, int vPixelCnt, char* buff)
{
    unsigned long offset=gHzkFullSize;
    char ch;
    int oneAscSize=hPixelCnt*vPixelCnt/8;

    if(NULL==c || *c==0){
        return false;
    }
    if(*c<0x14 || *c>0x7f){
        ch=' ';
    }else{
        ch=*c;
    }
    offset+=(ch-0x14)*oneAscSize;

    HZK=openHzkFile(gHzkFileName.c_str());
    if(NULL==HZK){
        LOG(ERROR)<<"getAscCode() ERROR: NULL==HZK!";
        return false;
    }
    fseek(HZK,offset,SEEK_SET);     /*将文件指针移动到偏移量的位置*/
    fread(buff,oneAscSize,1,HZK);           /*从偏移量的位置读取1个汉字字模数据，24*24=72字节*/
    fclose(HZK);
    std::string ch0;
    ch0+=ch;
    LOG(INFO)<<"getAscCode() offset:"<<offset<<",oneAscSize:"<<oneAscSize<<",char="<<ch0;
    //printBufferHex(buff, oneAscSize);
    //printHzkHex(buff, oneAscSize); 打印函数会报错，暂时不调了
    return true;
}
/**********************************
* 得到汉字字符的字模信息，存入数组
* 参数：
*   *c:要得到字模信息的字符指针(len == 2)
*   buffer[]:存储字模信息的数组
 *   HZK  no use
* 无返回值
***********************************/
bool getHzkCode(const char *c, FILE* HZK, int hPixelCnt, int vPixelCnt, char buff[])
{
    unsigned char qh,wh;
    unsigned long offset;
    int oneHzSize;
    LOG(INFO)<<"getHzkCode() HZ(0)="<<(int)c[0]<<",HZ(1)="<<(int)c[1]<<",hPixelCnt="<<hPixelCnt<<",vPixelCnt="<<vPixelCnt<<"";

    oneHzSize=hPixelCnt*vPixelCnt/8;

//    /*区码=内码(高字节)-160  位码=内码(低字节)-160*/
//    qh     = *(c) -0xa0;            /*10进制的160等于16进制的A0*/
//    wh     = *(c+1) -0xa0;          /*获得区码与位码*/
//    offset = (94*(qh-1)+(wh-1))*oneHzSize;/*计算该汉字在字库中偏移量*/
//    LOG(INFO)<<"getHzkCode() qh:"<<qh<<",wh:"<<wh<<",offset:"<<offset<<",oneHzSize:"<<oneHzSize;
    offset = font_gbk(c[0] * 256 + c[1]) * oneHzSize;

    HZK=openHzkFile(gHzkFileName.c_str());
    if(NULL==HZK){
        LOG(ERROR)<<"getHzkCode() ERROR: NULL==HZK!";
        return false;
    }
    fseek(HZK,offset,SEEK_SET);     /*将文件指针移动到偏移量的位置*/
    fread(buff,oneHzSize,1,HZK);           /*从偏移量的位置读取1个汉字字模数据，24*24=72字节*/
    fclose(HZK);
    LOG(INFO)<<"getHzkCode() offset:"<<offset<<",oneHzSize:"<<oneHzSize<<",char="<<c;
    //printBufferHex(buff, oneHzSize);
    //printHzkHex(buff, oneHzSize); 打印函数会报错，暂时不调了

    //已不需要点阵转换，使用字库即是转换后的（逐列逆向）
//    char* newBuff=new char[oneHzSize];
//    convertHzPixel(buff, newBuff, hPixelCnt, vPixelCnt, true, false, false, true);//转换为逐列逆序方式
//    printBufferHex(newBuff, oneHzSize);
//    delete[] newBuff;
    return true;
}
FILE* openHzkFile(const char* hzkFileName){
    FILE *HZK;
    /*打开字库文件hzk16*/
    if((HZK=fopen(hzkFileName, "rb"))==NULL){
        LOG(ERROR)<<"openHzkFile() ERROR: Can't open haz16,Please add it?";
        return NULL;
    }
    return HZK;
}
bool isGbkHzCode(char ch){
    if(ch>0x80){
        return true;
    }
    return false;
}

void setHzkFileName(const char* name){
    gHzkFileName = name;//保存汉字点阵字库文件名
}
/*
 * 获得strContent中包含的汉字点阵信息
 * 返回点阵数据（动态申请内存，需delete[]释放），hzCnt返回汉字数量（去掉重复汉字）， bufferSize返回点阵数据总长度
 */
char* getGbkHzPixelsByMap(const char* strContent, int& hzCnt, int& bufferSize){
    std::map<std::string,std::string> hzCodeMap;
    int contentLen=strlen(strContent);
    for(int i=0;i<contentLen;++i){
        if(isGbkHzCode(strContent[i])){
            std::string code;
            code+=strContent[i];
            if(++i>=contentLen){
                break;
            }
            code+=strContent[i];
            hzCodeMap[code]=code;
        }
    }
    hzCnt=hzCodeMap.size();
    if(hzCnt==0){
        bufferSize=0;
        LOG(INFO)<<"getGbkHzPixelsByMap() bufferSize=0, not find hz!";
        return NULL;
    }
    int oneHzDataSize=gHzSize*gHzSize/8;
    bufferSize=oneHzDataSize*hzCnt;
    char* pBuffer=new char[bufferSize];
    if(NULL==pBuffer){
        LOG(ERROR)<<"getGbkHzPixelsByMap() ERROR: NULL==pBuffer, alloc failed!";
        return NULL;
    }
    FILE* fileHandle=openHzkFile(gHzkFileName.c_str());
    if(NULL==fileHandle){
        LOG(ERROR)<<"getGbkHzPixelsByMap() ERROR: NULL==fileHandle!";
        delete[] pBuffer;
        return NULL;
    }
    //遍历map，得到每个汉字的点阵
    std::map<std::string,std::string>::iterator it;
    char* pOffset=pBuffer;
    bufferSize=0;
    for(it=hzCodeMap.begin();it!=hzCodeMap.end();++it){
        if(!getHzkCode(it->first.c_str(), fileHandle, gHzSize, gHzSize, pOffset)){
            return pBuffer;
        }
        bufferSize+=oneHzDataSize;
        pOffset+=oneHzDataSize;
    }
    return pBuffer;
}
/*
 * 获得strContent中包含的汉字点阵信息（不去掉重复汉字）
 * 返回点阵数据（动态申请内存，需delete[]释放），hzCnt返回汉字数量， bufferSize返回点阵数据总长度
 */
char* getGbkHzPixelsByVector(const char* strContent, int& hzCnt, int& bufferSize){
    std::vector<std::string> hzCodeVector;
    int contentLen=hzCnt;
    for(int i=0;i<contentLen;++i){
        if(isGbkHzCode(strContent[i])){
            std::string code;
            code+=strContent[i];
            if(++i>=contentLen){
                break;
            }
            code+=strContent[i];
            hzCodeVector.push_back(code);
        }else{
            std::string code;
            code+=strContent[i];
            hzCodeVector.push_back(code);//ascii
        }
    }
    hzCnt=hzCodeVector.size();
    if(hzCnt==0){
        bufferSize=0;
        LOG(INFO)<<"getGbkHzPixelsByVector() bufferSize=0, not find hz!";
        return NULL;
    }
    int oneHzDataSize=gHzSize*gHzSize/8;
    int oneAscSize=oneHzDataSize/2;
    bufferSize=oneHzDataSize*hzCnt;
    char* pBuffer=new char[bufferSize];
    if(NULL==pBuffer){
        LOG(ERROR)<<"getGbkHzPixelsByVector() ERROR: NULL==pBuffer, alloc failed!";
        return NULL;
    }
    FILE* fileHandle=NULL;
//    FILE* fileHandle=openHzkFile(gHzkFileName.c_str());
//    if(NULL==fileHandle){
//        LOG(ERROR)<<"getGbkHzPixelsByVector() ERROR: NULL==fileHandle!";
//        delete[] pBuffer;
//        return NULL;
//    }
    //遍历vector，得到每个汉字的点阵
    char* pOffset=pBuffer;
    bufferSize=0;
    for(int i=0;i<hzCnt;++i){
        int len=strlen(hzCodeVector[i].c_str());
        if(len==1){
            if(!getAscCode(hzCodeVector[i].c_str(), fileHandle, gHzSize/2, gHzSize, pOffset)) {
                return pBuffer;
            }
            bufferSize+=oneAscSize;
            pOffset+=oneAscSize;
        }else{
            if(!getHzkCode(hzCodeVector[i].c_str(), fileHandle, gHzSize, gHzSize, pOffset)) {
                return pBuffer;
            }
            bufferSize+=oneHzDataSize;
            pOffset+=oneHzDataSize;
        }
        //testPrintHzkdz(hzCodeVector[i].c_str());
    }
    return pBuffer;
}

/*
 * 工具函数：转换字库文件（源文件：逐行正向，目标文件：逐列逆向）,返回0成功，其他失败
 */
int convertHzkFile(const char* srcFile, const char* destFile, int hPixelCnt, int vPixelCnt)
{
    FILE *srcHzk,*destHzk;
    int oneHzSize, hzCount=0;
    long srcFileSize, currentPos;
    char* srcBuf, *destBuf;
    size_t retSize;
    int retCode=0;
    if(NULL==srcFile || *srcFile==0){
        LOG(ERROR)<<"convertHzkFile() ERROR: NULL==srcFile!";
        return 1;
    }
    if(NULL==destFile || *destFile==0){
        LOG(ERROR)<<"convertHzkFile() ERROR: NULL==destFile!";
        return 2;
    }
    LOG(INFO)<<"convertHzkFile() begin, srcFile="<<srcFile<<",destFile="<<destFile;
    /*打开字库文件hzk16*/
    if((srcHzk=fopen(srcFile, "rb"))==NULL){
        LOG(ERROR)<<"convertHzkFile() ERROR: fopen srcFile!";
        return 3;
    }
    if((destHzk=fopen(destFile, "wb"))==NULL){
        LOG(ERROR)<<"convertHzkFile() ERROR: fopen destFile!";
        fclose(srcHzk);
        return 4;
    }
    fseek(srcHzk,0L,SEEK_END);
    srcFileSize=ftell(srcHzk);
    oneHzSize=hPixelCnt*vPixelCnt/8;

    srcBuf=new char[oneHzSize];
    if(NULL==srcBuf){
        fclose(srcHzk);
        fclose(destHzk);
        LOG(ERROR)<<"convertHzkFile() ERROR: new srcBuf!";
        return 5;
    }
    destBuf=new char[oneHzSize];
    if(NULL==destBuf){
        delete[] srcBuf;
        fclose(srcHzk);
        fclose(destHzk);
        LOG(ERROR)<<"convertHzkFile() ERROR: new destBuf!";
        return 6;
    }
    fseek(srcHzk,0L,SEEK_SET);
    currentPos=ftell(srcHzk);
    while(currentPos>=0 && currentPos<srcFileSize){
        retSize=fread(srcBuf, 1, oneHzSize, srcHzk);
        if(retSize<oneHzSize){
            LOG(ERROR)<<"convertHzkFile() ERROR: fread srcBuf!";
            retCode=7;
            break;
        }
        //convertHzPixel(srcBuf, destBuf, hPixelCnt, vPixelCnt, true, false, false, true);//逐行正向，转换为逐列逆序方式
        convertHzPixel(srcBuf, destBuf, hPixelCnt, vPixelCnt, false, false, false, true);//逐列正向，转换为逐列逆序方式

        retSize=fwrite(destBuf, 1, oneHzSize, destHzk);
        if(retSize<oneHzSize){
            LOG(ERROR)<<"convertHzkFile() ERROR: fwrite destBuf!";
            retCode=8;
            break;
        }
        currentPos=ftell(srcHzk);
        ++hzCount;
    }
END_CONVERT:

    delete[] srcBuf;
    delete[] destBuf;
    fclose(srcHzk);
    fclose(destHzk);
    LOG(INFO)<<"convertHzkFile() end, hzCount="<<hzCount;
    return retCode;
}


void printByteToStr(char * str, int &k, char dzByte){
    char m;
    for(int i=7;i>=0;--i){
        m=1<<i;
        if(dzByte & m){
            str[k++]='*';
        }else{
            str[k++]=' ';
        }
    }
}
void testPrintHzkdz(const char* content){

    FILE* fileHandle=openHzkFile(gHzkFileName.c_str());
    if(NULL==fileHandle){
        LOG(ERROR)<<"getGbkHzPixelsByVector() ERROR: NULL==fileHandle!";
        return ;
    }
    //遍历vector，得到每个汉字的点阵
    char buffer[72];
    memset(buffer, 0, sizeof(buffer));
    if(!getHzkCode(content, fileHandle, gHzSize, gHzSize, buffer)){
        LOG(ERROR)<<"error";
        return ;
    }
    char str[30];
    int k=0;
    memset(str, 0, sizeof(str));
//逐行 正向（第1点是高位）
    for(int i=0;i<sizeof(buffer);i+=3){
        k=0;
        printByteToStr(str,k,buffer[i]);
        printByteToStr(str,k,buffer[i+1]);
        printByteToStr(str,k,buffer[i+2]);
        LOG(INFO)<<str;
    }
}
